`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/11/26 10:48:15
// Design Name: 
// Module Name: rv_ex_components
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

`include "rv_config.v"
module rvex_alu(input [31:0] src1,
    input [31:0] src2,
    input [2:0]  func3,
    input inst30,

    output reg [31:0] alu_out,
    output eq);

    wire [4:0] shamt;
    assign shamt = src2[4:0];

    always @(*) begin
    case(func3)
        3'b000: begin 
            if(inst30==1'b1) alu_out=src1-src2; 
            else alu_out=src1+src2; 
            end
        3'b001: begin
            alu_out = src1 << shamt; //shift left
        end
        3'b010: alu_out = ($signed(src1) < $signed(src2)) ? 32'd1 : 32'd0; //set-less-than (signed)
        3'b011: alu_out = (src1 < src2) ? 32'd1 : 32'd0; //set-less-than (unsigned)
        3'b100: alu_out = src1 ^ src2; //XOR
        3'b101: begin if(inst30==1'b1)  begin
                        alu_out = ($signed(src1)) >>> shamt; //shift right arithmetical
                      end
                        else begin
                            alu_out = src1 >> shamt; //shift right
                      end
                end
        3'b110: alu_out = src1 | src2; //OR
        3'b111: begin
            alu_out = src1 & src2; //AND
        end
    endcase
    end
    assign eq=(src1==src2)?1'b1:1'b0;

endmodule

module rvex_branch(
    input lt,
    input eq,
    input [4:0] inst_type,
    input [2:0] func3,
    input [31:0] pc,
    input [31:0] rs1,
    input [31:0] imm32,
    output reg update_pc_valid,
    output reg [31:0] update_pc
);
    wire need_branch;
    assign need_branch=(((func3==3'b000)&(eq==1'b1))| //BEQ
                        ((func3==3'b000)&(eq==1'b0))| //BNE
                        ((func3==3'b100)&(lt==1'b1))| //BLT
                        ((func3==3'b101)&((lt==1'b0)|(eq==1'b1)))| //BGE
                        ((func3==3'b110)&(lt==1'b1))| //BLTU
                        ((func3==3'b111)&((lt==1'b0)|(eq==1'b1))))? //BGEU
                        1'b1:1'b0;
                        
    always @(*) begin
        case(inst_type)
            `INST_BRANCH:  begin
                if(need_branch) begin
                    update_pc_valid=1'b1;
                    update_pc=pc+imm32;
                end
                else begin
                    update_pc_valid=1'b0;
                    update_pc=32'b0;
                end
            end
            `INST_JALR:  begin   //JALR
                update_pc_valid=1'b1;
                update_pc=pc+imm32;
            end
            `INST_JAL: begin   //JAL
                update_pc_valid=1'b1;
                update_pc=rs1+imm32;
            end
            default:    begin
                update_pc_valid=1'b0;
                update_pc=32'b0;
                end
        endcase
    end

endmodule